package com.wyc.price.service.impl;
import java.math.BigDecimal;
import java.util.List;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.wyc.internalCommon.constant.CommonStatusEnum;
import com.wyc.internalCommon.request.DirectionDTO;
import com.wyc.internalCommon.request.ForecastPriceDTO;
import com.wyc.internalCommon.request.PriceRuleDTO;
import com.wyc.internalCommon.response.ForecastPriceResponse;
import com.wyc.internalCommon.result.ApiResult;
import com.wyc.price.feign.ServiceMapFeignClient;
import com.wyc.price.mapper.PriceRuleMapper;
import com.wyc.price.service.ForecastPriceService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Slf4j
@Service
public class ForecastPriceServiceImpl implements ForecastPriceService {

    @Autowired
    private ServiceMapFeignClient serviceMapFeignClient;

    @Autowired
    private PriceRuleMapper priceRuleMapper;

    /**
     * 计算预算价格
     * @param forecastPriceDTO
     * @return
     */
    @Override
    public ApiResult<ForecastPriceResponse> forecastPrice(ForecastPriceDTO forecastPriceDTO) {

        // 调用地图服务，获取距离和时长
        ApiResult<DirectionDTO> directionDto = serviceMapFeignClient.driving(forecastPriceDTO);
        DirectionDTO direction = directionDto.getData();

        log.info("读取计价规则");
        QueryWrapper<PriceRuleDTO> wrapper = new QueryWrapper<>();
        wrapper.eq("city_code",forecastPriceDTO.getCityCode())
                        .eq("vehicle_type",forecastPriceDTO.getVehicleType())
                .orderByDesc("fare_version");
        List<PriceRuleDTO> list = priceRuleMapper.selectList(wrapper);
        PriceRuleDTO priceRuleDTO = list.get(0);
        // 计价规则不存在
        if (null == priceRuleDTO){
            return ApiResult.error(CommonStatusEnum.PRICE_RULE_EMPTY.getCode(),CommonStatusEnum.PRICE_RULE_EMPTY.getMsg());
        }

        log.info("根据距离，时长和计价规则，计算预算价格");
        BigDecimal price = getPrice(direction, priceRuleDTO);

        ForecastPriceResponse forecastPriceResponse = new ForecastPriceResponse();
        forecastPriceResponse.setPrice(price.doubleValue());
        forecastPriceResponse.setCityCode(priceRuleDTO.getCityCode());
        forecastPriceResponse.setVehicleType(priceRuleDTO.getVehicleType());
        forecastPriceResponse.setFareType(priceRuleDTO.getFareType());
        forecastPriceResponse.setFareVersion(priceRuleDTO.getFareVersion());
        return ApiResult.success(forecastPriceResponse);
    }

    /**
     * 计算实际价格
     * @param directionDTO
     * @return
     */
    @Override
    public ApiResult calulatePrice(DirectionDTO directionDTO) {
        // 查询计价规则
        QueryWrapper<PriceRuleDTO> wrapper = new QueryWrapper<>();
        wrapper.eq("city_code",directionDTO.getCityCode())
                .eq("vehicle_type",directionDTO.getVehicleType())
                .orderByDesc("fare_version");
        List<PriceRuleDTO> list = priceRuleMapper.selectList(wrapper);
        PriceRuleDTO priceRuleDTO = list.get(0);

        BigDecimal price = getPrice(directionDTO, priceRuleDTO);

        return ApiResult.success(price);
    }

    /**
     * 根据距离，时长和计价规则，计算预算价格
     * @param direction
     * @param priceRuleDTO
     * @return
     */
    private static BigDecimal getPrice(DirectionDTO direction, PriceRuleDTO priceRuleDTO) {
        // 距离 总里程 (米)
        BigDecimal distance = BigDecimal.valueOf(direction.getDistance());
        // 时长(秒)
        BigDecimal duration = BigDecimal.valueOf(direction.getDuration());

        // 起步价
        BigDecimal startFare = priceRuleDTO.getStartFare();
        // 起步里程 km
        BigDecimal startMile = BigDecimal.valueOf(priceRuleDTO.getStartMile());
        // 一公里价格
        BigDecimal unitPricePerMile = priceRuleDTO.getUnitPricePerMile();
        // 一分钟价格
        BigDecimal unitPricePerMinute = priceRuleDTO.getUnitPricePerMinute();

        // 最终预算价钱
        BigDecimal price = startFare.setScale(2,BigDecimal.ROUND_HALF_UP);

        log.info("计算里程费");
        // 剩余里程 (km) 除法要指定精度和舍入模式，否则出现无线循环报错
        BigDecimal distanceSubStartMile = distance.divide(BigDecimal.valueOf(1000),2,BigDecimal.ROUND_HALF_UP).subtract(startMile);
        if (distanceSubStartMile.compareTo(BigDecimal.valueOf(0)) == 1){
            // 剩余里程大于0km,收费
            price = price.add(distanceSubStartMile.multiply(unitPricePerMile)).setScale(2,BigDecimal.ROUND_HALF_UP);
        }
        log.info("计算时长费");
        // 秒换分钟
        BigDecimal timePrice = duration.divide(BigDecimal.valueOf(60),2,BigDecimal.ROUND_HALF_UP).multiply(unitPricePerMinute);
        price = price.add(timePrice).setScale(2,BigDecimal.ROUND_HALF_UP);
        return price;
    }

}
